/********************************************************************

Base exception class and related precompile defines
HOWTO: You can custom child exceptions and override getReason() function.
For exceptions of OOPException and all its descendants, USE OOPTHROW or
OOPTHROW_A to throw them, and the catch type is corresponding reference
type (or its ancestor).
OOPTHROW is for simple exception type which does not need to be set
additional information before thrown. The only parameter is the type of
the exception to throw. It will use default constructor to construct an
exception object of the type specified and throw it.
OPPTHROW_A is for complex exception type. The first parameter is the
exception object and the second one is its type.

Write Date: 2011/03/23
Author: Deng Nianchen
>>>> Implements an exception framework. Defines the base exception class

Modify Date: 2011/06/02
Author: Deng Nianchen
>>>> Change OOPException implementation. Using QString instead of wstring

Modify Date: 2015/08/17
Author: Apple
>>>> Update the code and comment style.
>>>> Rename MathExceptions.hpp to MathExceptions.h to match the file naming
     convention.

*********************************************************************/
#pragma once
#include "ooputils_global.h"
#include <QString>



#define OOPTHROW(__obj__) \
	::OOP::OOPException::throwWithDebugInfo (__obj__, __FILE__, \
			__FUNCTION__, __LINE__);



_NS_OOP_BEGIN



/**
 * Exception for signalling oop errors.
 *
 * @remarks 2011/3/22, Apple
 */
class OOPException
{
public:

	OOPException () : _lineNumber () {}

	virtual ~OOPException () {}

	/**
	 * Get the file name of the file which contains related throw statement.
	 *
	 * @return the file name
	 */
	QString getFileName () const { return _fileName; }

	/**
	 * Set the name of the file which contains related throw statement.
	 *
	 * @param fileName - filename of the file
	 */
	void setFileName (const QString & fileName) { _fileName = fileName; }

	/**
	 * Get the name of the function which contains related throw statement.
	 *
	 * @return the function name
	 */
	QString getFunctionName () const { return _functionName; }

	/**
	 * Set the name of the function which contains related throw statement.
	 *
	 * @param funcName - name of the function
	 */
	void setFunctionName (const QString & funcName) { _functionName = funcName; }

	/**
	 * Get the line number of related throw statement.
	 *
	 * @return the line number
	 */
	size_t getLineNumber () const { return _lineNumber; }

	/**
	 * Set line number of related throw statement.
	 *
	 * @param lineNumber - the line number
	 */
	void setLineNumber (size_t lineNumber) { _lineNumber = lineNumber; }

	/**
	 * Get the full description of the exception. That includes exception class
	 * name, file, function and line number of the related throw statement and
	 * the reason.
	 *
	 * @return the full description of the exception
	 */
	virtual QString getDescription () const {
		return QString ("%1 at %2 (%3:%4): %5").arg (typeid (*this).name ())
				.arg (_functionName).arg (_fileName).arg (_lineNumber)
				.arg (getReason ());
	}

	/**
	 * Get the reason of the exception. This function can be overrode in custom
	 * exception classes to return custom information.
	 *
	 * @return the reason of the exception
	 */
	virtual QString getReason () const {
		return "Unknown exception.";
	}

	/**
	 * Fill the exception object the debug information such as file, function
	 * and line, then throw the exception.
	 *
	 * @param r_ex - the exception to set debug info to
	 * @param file - the file
	 * @param func - the function
	 * @param line - the line
	 */
	template< class T >
	static void throwWithDebugInfo (T &r_ex, const char *file, const char *func,
			int line) {
		r_ex.setFileName (QString::fromLocal8Bit(file));
		r_ex.setFunctionName (QString::fromLocal8Bit (func));
		r_ex.setLineNumber (line);
		throw r_ex;
	}

private:

	QString _fileName;
	QString _functionName;
	size_t _lineNumber;

};



_NS_OOP_END